package com.open.basic.aop;

import com.open.basic.anno.LimitRequest;
import com.open.basic.util.LimitUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;


/**
 * @author: system
 * @Date: 2024/9/12 下午2:43
 * @Version: V1.0
 * @description: ->
 */

@Aspect
public class LimitRequestAop {


    /**
     * <pre>
     *
     * 这里我们使用注解的形式
     * 当然，我们也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method
     * 切点表达式:   execution(...)
     *
     * execution(public * *(..)) 任意的公共方法
     * execution（* set*（..）） 以set开头的所有的方法
     * execution（* com.LoggerApply.*（..））com.LoggerApply这个类里的所有的方法
     * execution（* com.annotation.*.*（..））com.annotation包下的所有的类的所有的方法
     * execution（* com.annotation..*.*（..））com.annotation包及子包下所有的类的所有的方法
     * execution(* com.annotation..*.*(String,?,Long)) com.annotation包及子包下所有的类的有三个参数，第一个参数为String类型，第二个参数为任意类型，第三个参数为Long类型的方法
     * execution(@annotation(com.lingyejun.annotation.Lingyejun))
     * </pre>
     */
    @Pointcut("@annotation(com.open.basic.anno.LimitRequest)")
    public void limitRequest() {

    }

    /**
     * 环绕通知 @Around  ， 当然也可以使用 @Before (前置通知)  @After (后置通知)
     *
     * @param point
     * @return
     * @throws Throwable
     */
    @Before("limitRequest()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        LimitRequest annotation = method.getAnnotation(LimitRequest.class);
        String type = annotation.type();
        String key = annotation.key();
        if (!StringUtils.hasLength(key)) {
            Object target = point.getTarget();
            String className = target.getClass().getName();
            key = className + "." + method.getName();
        }
        // if (annotation.userId().isEmpty()) {
        //     key = key + "_" + point.getArgs()[0];
        // } else {
        //     key = key + "_" + annotation.userId();
        // }
        switch(type) {
            case LimitRequest.REDIS:
                break;
            case LimitRequest.LEAKAGE_BUCKET:
            case LimitRequest.DEFAULT_LIMIT:
            default:
                LimitUtil.acquire(key, annotation.value());
                break;
        }
        return point.proceed();
    }
}
